﻿/** \file
* \$Rev: 187 $
* 
* \$Date: 2010-04-27 21:58:51 +0000 (Tue, 27 Apr 2010) $
*
* \$URL: http://chorus-twitter.googlecode.com/svn/trunk/src/utils/KeyedDictionary.cs $
*/

using System;
using System.Collections.Generic;
using chorus.twitter;

namespace chorus.utils
{
	/// <summary>
	/// An interface for items that can be referred to by some key to put
	/// into a dictionary.
	/// </summary>
	/// <typeparam name="KeyType">The key type.</typeparam>
	public interface IKeyed<KeyType>
	{
		/// <summary>The key to index with.</summary>
		KeyType Key { get; }
	}

	/// <summary>
	/// An extension of a regular dictionary that uses the Twitter Keyed class
	/// for extra knowledge of keys.
	/// </summary>
	/// <typeparam name="KeyType">The key type (usually ulong or string).</typeparam>
	/// <typeparam name="ValueType">The value type (status, user, etc.).</typeparam>
	public class KeyedDictionary<KeyType, ValueType> :
		Dictionary<KeyType, ValueType>
		where ValueType : Mergeable, IKeyed<KeyType>
	{
		/// <summary>Convert an integer index to an enumerator.</summary>
		/// <typeparam name="EnType">The enumerated value type.</typeparam>
		/// <param name="coll">The collection to enumerate.</param>
		/// <param name="index">The integer index.</param>
		/// <returns>The enumerator corresponding to the index.</returns>
		static IEnumerator<EnType> IndexToEnum<EnType>(ICollection<EnType> coll, int index)
		{
			IEnumerator<EnType> en = coll.GetEnumerator();
			en.MoveNext();
			for (int i = 0; i < index; i++)
				en.MoveNext();
			return en;
		}

		/// <summary>Convert an index to the corresponding dictionary key's enumerator.</summary>
		/// <param name="index">The integer index.</param>
		/// <returns>The key enumerator.</returns>
		public IEnumerator<KeyType> IndexToKEnum(int index) { return IndexToEnum(Keys, index); }

		/// <summary>Convert an index to the corresponding dictionary value's enumerator.</summary>
		/// <param name="index">The integer index.</param>
		/// <returns>The value enumerator.</returns>
		public IEnumerator<ValueType> IndexToVEnum(int index) { return IndexToEnum(Values, index); }

		/// <summary>
		/// Add a key-value pair to the dictionary. Overrides the default
		/// to use AddMerge instead.
		/// </summary>
		/// <param name="key">The dictionary key.</param>
		/// <param name="value">The value.</param>
		public new void Add(KeyType key, ValueType value) { AddMerge(key, value); }

		/// <summary>
		/// Add a value to the dictionary, extracting the key from the value
		/// automatically. If the value already exists in the dictionary,
		/// attempt to merge it instead of replacing it.
		/// </summary>
		/// <param name="value">The value to add.</param>
		/// <returns>The resulting value in the dictionary.</returns>
		public ValueType AddMerge(ValueType value)
		{
			if (value == null)
				return default(ValueType);
			return AddMerge(value.Key, value);
		}

		/// <summary>
		/// Add a value to the dictionary, extracting the key from the value
		/// automatically. If the value already exists in the dictionary,
		/// attempt to merge it instead of replacing it.
		/// </summary>
		/// <param name="key">The key at which the add will be done.</param>
		/// <param name="value">The value to add.</param>
		/// <returns>The resulting value in the dictionary.</returns>
		public ValueType AddMerge(KeyType key, ValueType value)
		{
			if (value == null)
				return default(ValueType);
			ValueType oldval;
			if (TryGetValue(key, out oldval))
			{
				oldval.MergeFrom(value);
				return oldval;
			}
			base.Add(key, value);
			return value;
		}

		/// <summary>Remove an entry from the dictionary.</summary>
		/// <param name="value">The value to remove.</param>
		/// <returns>True if the value was present in the dictionary and removed.</returns>
		public bool Remove(ValueType value)
		{
			if (value == null)
				return false;
			return base.Remove(value.Key);
		}
	}
}
